/*
 * Cserver.cpp
 *
 *  Created on: Dec 4, 2010
 *      Author: lycdragon
 */

#include "Cserver.h"
#include <cctype>

typedef vector<string> vectorstring;
map< string, vectorstring > csmap;
map< string, vectorstring >::iterator csmapit;

string tolow(string s)
{
	int l = s.length();
	for(int i = 0; i < l; i++)
		s[i] = tolower(s[i]);
	return s;
}

bool isthesame(string base, string extend)
{
	base = tolow(base.substr(0, base.find(".")));
	extend = tolow(extend.substr(0, extend.find(".")));
	int l = base.length();
	for(int i = 0; i < l; i++)
		if(base[i] != extend[i]) return false;
	return true;
}

void printChunkInfo();

void* CSdoClientThread(void *pParam)
{
	char buf[MAXDATASIZE];
	struct parm *p = (struct parm*)(pParam);
	char ipaddr[20];
	int numbytes;
	string encodedString;
	Message msg;
	bool success;
	int clientSocket = p -> sd;
	strcpy(ipaddr, inet_ntoa(p -> cad.sin_addr));

	if ((numbytes = recv(clientSocket, buf,  MAXDATASIZE, 0)) == -1){
		cerr << "Receive message fail" << endl;
	}
	encodedString.assign(buf);
	success = msg.decode(encodedString);

	if (success) {
		//request for file
		if (msg.getMessageType() == LS_2_CS_REQ) {
			string requestedFile=msg.getMessage();
			vector <string> v;
			v.clear();

			for(csmapit = csmap.begin(); csmapit != csmap.end(); csmapit++)
			{
				if(isthesame(requestedFile, (*csmapit).first))
					v.insert(v.end(), (*csmapit).second.begin(), (*csmapit).second.end());
			}

			MessageChunkInfo cs2lsChunkInfo(v,CS_2_LS_REP);
			cout<<"Answer is ready:"<<endl;
			for(vector<string>::iterator it = v.begin(); it != v.end(); ++it){
				string chunk=*it;
				cout<<chunk<<endl;
			}
			encodedString = cs2lsChunkInfo.encode();
			strcpy(buf, encodedString.c_str());
			send(clientSocket, buf, encodedString.length(), 0);
		}

		//update chunk information
		else if (msg.getMessageType() == MSG_CHUNK_INFO_ADV) {
			cout << "Received chunk information message from: "<<ipaddr << endl;
			string ip;
			ip.assign(ipaddr);
			MessageChunkInfo ls2csChunkInfo1=MessageChunkInfo(MSG_CHUNK_INFO_ADV);
			ls2csChunkInfo1.setChunksFromRawMsg(encodedString);

			for(csmapit = csmap.begin(); csmapit != csmap.end(); csmapit++)
			{
				for(vector<string>::iterator it1 = (*csmapit).second.begin(); it1 != (*csmapit).second.end(); it1++){
					if(ip == (*it1).substr(0, (*it1).find(":"))){
						(*csmapit).second.erase(it1);
					}
				}
			}

			//Access the chunks
			std::vector<string> chunks=ls2csChunkInfo1.getChunks();
			for(vector<string>::iterator it = chunks.begin(); it != chunks.end(); ++it){
				string ipPortChunk=ip+":"+*it;
				string portChunk=*it;
				string chunk;
				int index=portChunk.find(":");
				chunk=portChunk.substr(index+1);
				vector<string> existingSources=csmap[chunk];
				csmap[chunk].push_back(ipPortChunk);
			}
			printChunkInfo();
		}

		//process if it is a bye message
		else if (msg.getMessageType() == LS_2_CS_BYE) {
			cout << "Central server got bye message from:"<<ipaddr << endl;
		}
	} else {
		cout << "Unable to decode the message..." << endl;
	}

close(clientSocket);


}

void printChunkInfo(){
	map<string,vectorstring>::iterator it;
	vectorstring chunks;
	string key;
	int count=1;
	cout<<"--------- Chunk Information in Central Server ---------"<<endl;
	for ( it=csmap.begin() ; it != csmap.end(); it++ ){
		key=(*it).first;
		chunks=(*it).second;
		for(vector<string>::iterator it1 = chunks.begin(); it1 != chunks.end(); ++it1){
			cout<<key<<"--->"<<(*it1)<<endl;
		}
	}
	cout<<"--------------------------------------------------------"<<endl;

}


Cserver::Cserver(int port_number) {
	string name("Central Server");
	struct  sockaddr_in cad;
	size_t  alen;
	int sd2;
	int sd = asServer(name, port_number);
	bool firstTime=true;

    while (1)
    {
    	/* Specify size of request queue */
    	if (listen(sd, QLEN) < 0)
    	{
   	        cerr << "listen failed" << endl;
   	        exit(0);
   	    }
		cout.flush();

		if(firstTime){
        	cout << name << " is waiting for a client connection in PORT:"<<port_number << endl;
        	firstTime=false;
        }

		alen = sizeof(cad);
        if ( (sd2 = accept(sd, (struct sockaddr *)&cad, &alen)) < 0)
    	{
            cerr << name << ":"<< "accept failed" << endl;
        }


  		cout << name << " received and accepted a client connection from :" << inet_ntoa(cad.sin_addr) << endl;

        if(send(sd2,"Connect success!", 17 ,0) < 0)
        {
        	cerr << name << ":" << "Send connection information failed" << endl;
        	continue;
        }

        struct parm temp;
        temp.sd = sd2;
        temp.cad = cad;

        pthread_attr_t ma;
        pthread_attr_init(&ma);
        pthread_attr_setdetachstate(&ma, PTHREAD_CREATE_JOINABLE);
        pthread_t pt;

        if(pthread_create(&pt, &ma, CSdoClientThread,(void*)(&temp)) != 0)
        {
        	cerr << "Fail to create thread for client" << sd2;
        }

        pthread_attr_destroy(&ma);
    }
}
